#ifndef __BLOCK_QUEUE__
#define __BLOCK_QUEUE__
#include <cstdlib>
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <queue>

using std::cout;
using std::endl;

// 阻塞队列的实现
// 生产消费模型的实践
// 生产和消费并发进行，3：三种关系（
//       当前实现是单生产，单消费，于是不需要考虑生产者与生产者之间、消费者与消费者之间的关系
//       仅仅考虑单个生产者和消费者之间的关系
// ——————当队列满，停止生产；队列为空，停止消费（线程同步）

// ） 2：两个角色（consumer，creator） 1：一个交易场所（queue）

template <class T>
class BlockQueue
{
private:
    bool Isfull()
    {
        return _queue.size() == _maxcap;
    }
    bool Isempty()
    {
        return _queue.empty();
    }

public:
    BlockQueue(int maxcap = 10)
        : _maxcap(maxcap), _queue(), _l_water(0), _h_water(maxcap),_call_num(maxcap/2)
    {
        if (maxcap <= 4)//数据总体个数太少，不在处理这些细节
        {
            _l_water = 0x3f3f3f3f;//无穷大
            _h_water = -0x3f3f3f3f;//无穷小
            _call_num = 1;
        }
        else
        {
            _l_water = maxcap / 4;
            _h_water = maxcap * 3 / 4;
        }

        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_p_cond, nullptr);
        pthread_cond_init(&_c_cond, nullptr);
    }

    // 生产者向队列中生产数据
    void Push(T &in)
    {
        pthread_mutex_lock(&_mutex);
        while (Isfull())
        // 队列满了，停止生产，在pcond条件变量下等待
        {
            pthread_cond_wait(&_p_cond, &_mutex);
        }
        // 走到这里，要么等待之后被唤醒，要么队列没有满，可以加入数据
        _queue.push(in);

        pthread_cond_signal(&_c_cond);
        
        // 数据较多，叫醒消费者来消费
        if (_queue.size() >= _h_water)
        {
            cout<<"call lots comsumer"<<endl;
            int t = _call_num;
            while (t--)
                pthread_cond_signal(&_c_cond);
        }

        pthread_mutex_unlock(&_mutex);
    }

    // 消费者拿队列内的数据
    void Pop(T *out)
    {
        pthread_mutex_lock(&_mutex);
        while (Isempty())
        // 队列空了，停止消费，在ccond条件变量下等待
        {
            pthread_cond_wait(&_c_cond, &_mutex);
        }
        // 走到这里，要么等待之后被唤醒，要么队列没有空，可以拿出数据
        *out = _queue.front();
        _queue.pop();

        pthread_cond_signal(&_p_cond);

        // 数据较少，叫醒生产者来生产
        if (_queue.size() <= _l_water)
        {
            cout<<"call lots creator"<<endl;

            int t = _call_num;
            while (t--)
                pthread_cond_signal(&_p_cond);
        }

        pthread_mutex_unlock(&_mutex);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_p_cond);
        pthread_cond_destroy(&_c_cond);
    }
    size_t GetSize()
    {
        return _queue.size();
    }

private:
    std::queue<int> _queue; // 交易场所

    int _maxcap;            // 队列最大数据个数
    pthread_mutex_t _mutex; // 维护生产和消费的互斥关系

    // creator consummer wait in different blockqueue
    pthread_cond_t _p_cond;
    pthread_cond_t _c_cond;

    int _l_water; // 低水平线，低于这条线，叫醒更多的生产者生产
    int _h_water; // 高水平线，高于这条线，叫醒更多的消费者消费

    int _call_num;//一次叫醒大量的合适值
};
#endif